
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.*;
import java.sql.*;
import java.util.BitSet;
import trigest.trigest;

public class SThreadQuery extends Thread {

    private Socket socket = null;
    private String Information = null;

    public SThreadQuery(Socket socket, String Info) {
        super("Query Thread");
        this.socket = socket;
        this.Information = Info;
    }

    public void run() {

        String information = null, message = null, sequenceN = null, Query = null, username = null, answer = null;
        int pointer = 0, max = 0, counter = 0, answers = 0, pointers[], results[], count = 0, flag = 0;
        BitSet bit1, bit, bitoriginal;
        String ip[], filename[], Digest[], hash[];
        byte[] signature = new byte[1024];

        trigest Q;


        try {

            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(
                    new InputStreamReader(
                    socket.getInputStream()));

            pointers = new int[8192];
            for (int i = 0; i < 8192; i++) {
                pointers[i] = 0;
            }


            try {

                information = Information;
                information = information.substring(2);
                pointer = information.indexOf("|");
                username = information.substring(0, pointer);
                information = information.substring(pointer + 1);
                pointer = information.indexOf("|");
                sequenceN = information.substring(0, pointer);
                information = information.substring(pointer + 1);
                pointer = information.indexOf("|");
                Query = information.substring(0, pointer);
                Q = new trigest(Query);
                signature = Q.getSignature();
                message = "Q|" + username + "|" + max + "|";
            } catch (Exception e) {
                out.write("!|1| " + e.toString() + "|" + '\n');
                System.out.println("!|1");
            }


            try {
                Statement SQLstmt;
                ResultSet rs;
                Class.forName("com.mysql.jdbc.Driver");
                String url = "jdbc:mysql://localhost:3306/mysql";

                Connection con = DriverManager.getConnection(url, "root", "admin");


                SQLstmt = con.createStatement();

                System.out.println("max:1 " + "1");

                rs = SQLstmt.executeQuery("SELECT * FROM organize.publish ORDER BY TimeModified");

                Statement sql = con.createStatement();
                ResultSet rs1 = sql.executeQuery("SELECT count(*) FROM organize.publish");
                rs1.next();
                max = rs1.getInt(1);

                //max=rs.getFetchSize();
                System.out.println("max: " + max);

                if (max == 0) {
                    out.write("!|8" + '\n');
                    System.out.println("!|8");
                } else {

                    hash = new String[max];
                    ip = new String[max];
                    filename = new String[max];
                    Digest = new String[max];

                    results = new int[max];
                    for (int i = 0; i < max; i++) {
                        results[i] = 0;
                    }
                    counter = 0;

                    while (rs.next()) {
                        hash[counter] = rs.getString("Hash");
                        Digest[counter] = rs.getString("Digest");
                        filename[counter] = rs.getString("FileName");
                        ip[counter] = rs.getString("IPAddress");
                        counter++;
                    }
                    count = 0;
                    int x = 0, y = 0;
                    for (int i = 0; i < max; i++) {

                        pointers = fromString(hash[i]);

                        bit = BitSetFromIntArray(pointers);//file
                        bit1 = fromByteArray(signature);//keyword
                        bitoriginal = bit1;//copy keyword
                        x = bitoriginal.cardinality();//number of 1 bits in the query
                        y = bit1.cardinality(); // number of 1 bits in the query
                        bit1.and(bit); //AND the bits of the query with the bits of the file 1 1 = 1, 0 0 = 0 , 1 0 = 0
                        y = bit1.cardinality();
                        System.out.println(x + " " + y);
                        if (x == y) //check same number of 1s still means all bits of the query matched with the file bits
                        {

                            results[count] = i;

                            count++;

                            flag = 0;
                        }

                        x = 0;
                        y = 0;

                    }
                    System.out.println(count);
                    message = null;

                    if (count == 0) {
                        message = "Q|0|";
                        message += '\n';
                        out.write(message);
                        out.flush();
                    } else {


                        //message="Q|" + username + "|" + max + "|";

                        message = "Q|" + username + "|" + count + "|";

                        System.out.println("count: " + count);

                        for (int i = 0; i < count; i++) {
                            message += filename[results[i]] + "~" + Digest[results[i]] + "~" + ip[results[i]] + "|";
                        }

                        message += '\n';
                        out.write(message);
                        out.flush();


                    }

                    try {
                        while (!in.ready()) {
                            SThreadQuery.sleep(50);

                        }
                    } catch (InterruptedException e) {
                    }

                    answer = in.readLine();

                    rs.close();
                    SQLstmt.close();
                    con.close();
                }

            } catch (Exception e) {
                out.write("!|11|Could not access database| " + e.toString() + '\n');
                System.out.println("!|11");
            }

            out.close();
            in.close();
            socket.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static BitSet fromByteArray(byte[] bytes) {
        BitSet bits = new BitSet();
        for (int i = 0; i < bytes.length * 8; i++) {
            if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0) {
                bits.set(i);
            }
        }
        return bits;
    }

    private static int[] fromString(String value) {

        int pointers[], counter = 0;
        int pointer = 0;

        pointers = new int[8192];
        for (int i = 0; i < 8192; i++) {
            pointers[i] = 0;
        }

        value = value.substring(1);
        counter++;
        while (value.contains(", ")) {
            pointer = value.indexOf(',');
            pointers[counter] = Integer.parseInt(value.substring(0, pointer));
            value = value.substring(pointer + 2);
            counter++;
        }

        pointer = value.indexOf('}');
        try {
            pointers[counter] = Integer.parseInt(value.substring(0, pointer));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        pointers[0] = counter;


        return pointers;
    }

    private static BitSet BitSetFromIntArray(int[] value) {

        BitSet bits = new BitSet();

        for (int i = 1; i <= value[0]; i++) {
            bits.set(value[i]);
        }


        return bits;
    }
}
